package services;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import models.Resource;
import models.ResourceType;
import models.Setting;

public class ConfigurationService extends ResourceService {
	
	private static final String RESOURCES_DIRECTORY = "resources/configs/";
	
	private final SettingService settingService = SettingService.getService();
	
	private static ConfigurationService service;
	
	// Singleton pattern
	private ConfigurationService() {
		
	}
	
	public static ConfigurationService getService() {
		if (service == null)
			service = new ConfigurationService();
		return service;
	}
	
	public List<Resource> getAllConfigs() {
		return Resource.find.where().eq("type", ResourceType.TestConfiguration).findList();
	}
	
	public Resource getConfig(long configId) {
		return Resource.find.byId(configId);
	}
	
	public boolean configExists(long configId) {
		return getConfig(configId) != null;
	}
	
	/**
	 * Add Resource entity of type config in DB and persist configuration to a file system using resource path and id as a file name
	 * 
	 * @param config
	 * @param content
	 * @return
	 */
	public Resource saveConfig(Resource config, String content) {
		Resource result = config;
		if (config.getId() <= 0) {
			result = createConfig(config);
		} else {
			result = updateConfig(config);
		}
		if (!result.isRemote() && StringUtils.isNotBlank(content)) {
			storeConfigFile(result, content);
		}
		return result;
	}
	
	private Resource createConfig(Resource config) {
		Date currentDate = new Date();
		config.setType(ResourceType.TestConfiguration);
		config.setCreateDate(currentDate);
		config.setLastModified(currentDate);
		config.save();
		config.setResourcePath(RESOURCES_DIRECTORY + config.getId());
		config.save();
		return config;
	}
	
	private Resource updateConfig(Resource config) {
		config.setLastModified(new Date());
		config.save();
		return config;
	}
	
	/**
	 * Fetch config properties from a config file
	 * 
	 * @param config
	 * @return
	 */
	public String getConfigFileContent(Resource config) {
		String content = "";
		if (config != null) {
			if (config.isRemote()) {
				content = getRemoteConfigFileContent(config);
			} else {
				content = getLocalConfigFileContent(config);
			}
		}
		return content;
	}
	
	private String getLocalConfigFileContent(Resource config) {
		return getFileContent(config.getResourcePath(), getConfigFileName(config));
	}
	
	private String getRemoteConfigFileContent(Resource config) {
		return getFileContent(settingService.getSetting(Setting.REMOTE_CONFIG_HOME).getStringValue(), config.getName());
	}
	
	private String getFileContent(String parentDirectory, String fileName) {
		try {
			File configFile = new File(new File(parentDirectory), fileName);
			if (configFile.exists()) {
				BufferedReader br = new BufferedReader(new FileReader(configFile));
				try {
					StringBuilder sb = new StringBuilder();
					String line = br.readLine();
					
					while (line != null) {
						sb.append(line);
						sb.append("\n");
						line = br.readLine();
					}
					return sb.toString();
				} finally {
					br.close();
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}
	
	/**
	 * Persist config to config file
	 * 
	 * @param stringConfig
	 * @param config
	 */
	public void storeConfigFile(Resource config, String stringConfig) {
		try {
			File configDirectory = new File(config.getResourcePath());
			if (!configDirectory.exists()) {
				configDirectory.mkdirs();
			}
			File configFile = new File(configDirectory, getConfigFileName(config));
			
			BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
			writer.write(stringConfig);
			writer.close();
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private String getConfigFileName(Resource config) {
		return String.format("%d.py", config.getId());
	}
	
	public Resource getConfig(String configName) {
		List<Resource> configs = Resource.find.where().eq("name", configName).eq("type", ResourceType.TestConfiguration).findList();
		
		if (configs == null || configs.isEmpty())
			return null;
		else
			return configs.get(0);
	}
	
	public void saveRemoteConfig(Resource config) {
		saveConfig(config, null);
	}
	
}
